
from django.db import models
from django.contrib.auth import get_user_model
from django.conf import settings
import uuid
import os
import json
import shutil
from pathlib import Path

User = get_user_model()

class ProjectModel(models.Model):
    """项目模型"""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255, verbose_name="项目名称")
    description = models.TextField(blank=True, null=True, verbose_name="项目描述")
    creator = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="创建者")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    # 项目本地路径
    project_path = models.CharField(max_length=500, verbose_name="项目本地路径", default="temp_path")
    
    # markdown 内容和版本管理
    current_content = models.TextField(blank=True, null=True, verbose_name="当前markdown内容")
    version_count = models.IntegerField(default=0, verbose_name="版本计数")
    
    class Meta:
        db_table = "project"
        ordering = ["-created_at"]
        verbose_name = "项目"
        verbose_name_plural = "项目"

    def __str__(self):
        return self.name
    
    def save(self, *args, **kwargs):
        """保存时自动创建项目目录"""
        # 🔧 修复路径设置逻辑
        is_new_project = not self.pk  # 判断是否为新项目
        
        if is_new_project or self.project_path == "temp_path":
            # 先保存获得ID
            if is_new_project:
                super().save(*args, **kwargs)
            
            # 生成正确的项目路径: MEDIA_ROOT/projects/用户ID/项目ID/
            base_path = getattr(settings, 'MEDIA_ROOT', 'media')
            self.project_path = os.path.join(
                base_path, 
                'projects', 
                str(self.creator.id), 
                str(self.id)
            )
            
            print(f"🔧 设置项目路径: {self.project_path}")
            
            # 再次保存更新路径
            if is_new_project:
                super().save(update_fields=['project_path'])
            else:
                super().save(*args, **kwargs)
        else:
            super().save(*args, **kwargs)
        
        # 确保项目目录存在
        self.ensure_project_directory()
    
    def ensure_project_directory(self):
        """确保项目目录存在"""
        Path(self.project_path).mkdir(parents=True, exist_ok=True)
        
        # 创建子目录
        subdirs = ['assets', 'images', 'docs', 'temp']
        for subdir in subdirs:
            Path(self.project_path, subdir).mkdir(exist_ok=True)
    
    def get_background_md_path(self):
        """获取background.md文件路径"""
        return os.path.join(self.project_path, 'background.md')
    
    def get_index_md_path(self):
        """获取index.md文件路径"""
        return os.path.join(self.project_path, 'index.md')
    
    def get_directory_tree(self):
        """生成项目目录树"""
        def build_tree(path, name=None):
            tree = {}
            if name is None:
                name = os.path.basename(path)
            
            tree['name'] = name
            tree['type'] = 'directory' if os.path.isdir(path) else 'file'
            tree['path'] = os.path.relpath(path, self.project_path)
            
            if os.path.isdir(path):
                tree['children'] = []
                try:
                    for item in sorted(os.listdir(path)):
                        if not item.startswith('.'):  # 忽略隐藏文件
                            item_path = os.path.join(path, item)
                            tree['children'].append(build_tree(item_path, item))
                except PermissionError:
                    pass
            else:
                # 文件信息
                try:
                    stat = os.stat(path)
                    tree['size'] = stat.st_size
                    tree['modified'] = stat.st_mtime
                except:
                    pass
            
            return tree
        
        if os.path.exists(self.project_path):
            return build_tree(self.project_path, self.name)
        return {}
    
    def update_background_md(self):
        """更新background.md文件"""
        tree = self.get_directory_tree()
        
        # 生成background.md内容
        content = self._generate_background_content(tree)
        
        # 写入文件
        background_path = self.get_background_md_path()
        with open(background_path, 'w', encoding='utf-8') as f:
            f.write(content)
        
        return content
    
    def _generate_background_content(self, tree):
        """生成background.md的内容"""
        content = f"""# {self.name} - 背景知识

## 项目结构

"""
        
        # 添加目录树
        content += self._tree_to_markdown(tree)
        
        # 添加文件内容摘要
        content += "\n\n## 文件内容摘要\n\n"
        content += self._generate_file_summaries()
        
        return content
    
    def _tree_to_markdown(self, tree, level=0):
        """将目录树转换为markdown格式"""
        if not tree:
            return ""
        
        indent = "  " * level
        content = ""
        
        if tree['type'] == 'directory':
            content += f"{indent}- 📁 **{tree['name']}/\n"
            if 'children' in tree:
                for child in tree['children']:
                    content += self._tree_to_markdown(child, level + 1)
        else:
            # 根据文件扩展名选择图标
            ext = os.path.splitext(tree['name'])[1].lower()
            icon = {
                '.md': '📝', '.txt': '📄', '.pdf': '📕',
                '.jpg': '🖼️', '.jpeg': '🖼️', '.png': '🖼️', '.gif': '🖼️',
                '.mp4': '🎬', '.avi': '🎬', '.mov': '🎬',
                '.zip': '📦', '.tar': '📦', '.gz': '📦'
            }.get(ext, '📄')
            
            size_mb = tree.get('size', 0) / (1024 * 1024) if tree.get('size') else 0
            size_str = f" ({size_mb:.1f}MB)" if size_mb > 0.1 else ""
            
            content += f"{indent}- {icon} {tree['name']}{size_str}\n"
        
        return content
    
    def _generate_file_summaries(self):
        """生成项目中markdown文件的内容摘要"""
        summaries = []
        
        # 遍历项目目录，找到所有markdown文件
        for root, dirs, files in os.walk(self.project_path):
            for file in files:
                if file.endswith('.md') and file != 'background.md':
                    file_path = os.path.join(root, file)
                    relative_path = os.path.relpath(file_path, self.project_path)
                    
                    try:
                        with open(file_path, 'r', encoding='utf-8') as f:
                            content = f.read()
                            # 取前200个字符作为摘要
                            summary = content[:200] + "..." if len(content) > 200 else content
                            summaries.append(f"### {relative_path}\n```\n{summary}\n```\n")
                    except:
                        summaries.append(f"### {relative_path}\n无法读取文件内容\n")
        
        return "\n".join(summaries) if summaries else "暂无markdown文件"
    
    def _collect_all_file_contents(self):
        """收集项目中所有可读文件的内容用于AI分析"""
        file_contents = {}
        
        # 支持的文件类型
        supported_extensions = ['.md', '.txt', '.py', '.js', '.html', '.css', '.json', '.yml', '.yaml', '.xml']
        
        for root, dirs, files in os.walk(self.project_path):
            # 跳过某些目录
            dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['__pycache__', 'node_modules']]
            
            for file in files:
                if file == 'background.md':  # 跳过background.md本身
                    continue
                    
                file_path = os.path.join(root, file)
                relative_path = os.path.relpath(file_path, self.project_path)
                
                # 检查文件扩展名
                file_ext = os.path.splitext(file)[1].lower()
                
                if file_ext in supported_extensions:
                    try:
                        with open(file_path, 'r', encoding='utf-8') as f:
                            content = f.read()
                            # 限制单个文件内容长度，避免token过多
                            if len(content) > 2000:
                                content = content[:2000] + "...\n[文件内容截断]"
                            file_contents[relative_path] = content
                    except Exception as e:
                        file_contents[relative_path] = f"[无法读取文件: {str(e)}]"
                else:
                    # 对于不支持的文件类型，只记录基本信息
                    try:
                        stat = os.stat(file_path)
                        size_mb = stat.st_size / (1024 * 1024)
                        file_contents[relative_path] = f"[二进制文件: {size_mb:.2f}MB]"
                    except:
                        file_contents[relative_path] = "[无法访问的文件]"
        
        return file_contents
    
    def generate_ai_background_md(self):
        """使用AI生成智能化的background.md - 项目结构 + 文件总结"""
        try:
            # 🎯 第一部分：项目结构
            directory_tree = self.get_directory_tree()
            tree_markdown = self._tree_to_markdown(directory_tree)
            
            # 🎯 第二部分：收集所有文件并逐个AI总结
            all_files = self._collect_project_files()
            
            # 构建background.md内容
            content_parts = []
            
            # 添加项目基本信息
            content_parts.append(f"""# {self.name} - 背景知识

## 项目结构
{tree_markdown}

## 文件内容总结
""")
            
            # 🤖 为每个文件生成AI总结
            if all_files:
                for file_info in all_files:
                    file_summary = self._generate_file_summary_with_ai(file_info)
                    content_parts.append(file_summary)
            else:
                content_parts.append("暂无文件")
            
            # 合并所有内容
            final_content = "\n".join(content_parts)
            
            # 写入background.md
            background_path = self.get_background_md_path()
            with open(background_path, 'w', encoding='utf-8') as f:
                f.write(final_content)
            
            print(f"✅ AI智能背景文档生成完成，包含 {len(all_files) if all_files else 0} 个文件的总结")
            
        except Exception as e:
            print(f"❌ AI背景生成失败: {str(e)}")
            # 回退到简单版本
            self.update_background_md()
            raise e
    
    def _collect_project_files(self):
        """收集项目中的所有文件信息"""
        files = []
        project_path = Path(self.project_path)
        
        if not project_path.exists():
            return files
        
        # 遍历项目目录，收集文件信息
        for root, dirs, filenames in os.walk(project_path):
            # 跳过临时目录
            if 'temp' in Path(root).parts:
                continue
                
            for filename in filenames:
                file_path = Path(root) / filename
                
                # 跳过background.md和index.md（避免循环）
                if filename in ['background.md', 'index.md']:
                    continue
                
                # 获取相对路径
                relative_path = file_path.relative_to(project_path)
                
                # 尝试读取文件内容
                content = ""
                try:
                    # 只处理文本文件
                    if filename.endswith(('.md', '.txt', '.py', '.js', '.json', '.yml', '.yaml', '.xml', '.html', '.css', '.sql')):
                        with open(file_path, 'r', encoding='utf-8') as f:
                            content = f.read()
                    elif filename.endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg')):
                        content = f"[图片文件: {filename}]"
                    else:
                        content = f"[二进制文件: {filename}]"
                except Exception as e:
                    content = f"[无法读取文件: {str(e)}]"
                
                files.append({
                    'filename': filename,
                    'relative_path': str(relative_path),
                    'content': content,
                    'size': file_path.stat().st_size if file_path.exists() else 0
                })
        
        return files
    
    def _generate_file_summary_with_ai(self, file_info):
        """使用AI为单个文件生成总结"""
        filename = file_info['filename']
        relative_path = file_info['relative_path']
        content = file_info['content']
        
        # 🤖 AI总结提示
        system_prompt = f"""请为以下文件生成一个简洁的总结：

文件名: {filename}
文件路径: {relative_path}
文件内容:
```
{content[:2000]}{"..." if len(content) > 2000 else ""}
```

请提供：
1. 文件类型和用途
2. 主要内容概述（2-3句话）
3. 关键信息提取

用中文回复，简洁明了。"""

        try:
            import openai
            from django.conf import settings
            
            # 配置OpenAI客户端
            client = openai.OpenAI(
                api_key=settings.OPENAI_API_KEY,
                base_url=settings.OPENAI_API_BASE
            )
            
            response = client.chat.completions.create(
                model=settings.OPENAI_MODEL,
                messages=[
                    {"role": "system", "content": system_prompt}
                ],
                max_tokens=300,
                temperature=0.7
            )
            
            ai_summary = response.choices[0].message.content
            
            return f"""### 📄 {filename}
**路径**: `{relative_path}`  
**大小**: {file_info['size']} bytes

{ai_summary}

---
"""
        
        except Exception as e:
            # AI失败时返回基本信息
            content_preview = content[:200] + "..." if len(content) > 200 else content
            return f"""### 📄 {filename}
**路径**: `{relative_path}`  
**大小**: {file_info['size']} bytes

**文件内容**:
```
{content_preview}
```

---
"""
    
    def get_background_content(self):
        """获取background.md的内容"""
        background_path = self.get_background_md_path()
        if os.path.exists(background_path):
            with open(background_path, 'r', encoding='utf-8') as f:
                return f.read()
        else:
            # 如果文件不存在，生成一个
            return self.update_background_md()
    
    def write_index_md(self, content):
        """写入index.md文件内容"""
        index_path = self.get_index_md_path()
        
        with open(index_path, 'w', encoding='utf-8') as f:
            f.write(content)
        
        # 同时更新current_content字段
        self.current_content = content
        self.save()
        
        return index_path
    
    def get_index_md_content(self):
        """获取index.md的内容"""
        index_path = self.get_index_md_path()
        if os.path.exists(index_path):
            with open(index_path, 'r', encoding='utf-8') as f:
                return f.read()
        else:
            # 如果文件不存在，返回当前内容或空字符串
            return self.current_content or ""
    
    def add_uploaded_file(self, file, target_subdir='docs'):
        """添加上传的文件到项目目录"""
        target_dir = os.path.join(self.project_path, target_subdir)
        Path(target_dir).mkdir(exist_ok=True)
        
        file_path = os.path.join(target_dir, file.name)
        
        with open(file_path, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
        
        # 更新background.md
        self.update_background_md()
        
        return file_path
    
    def delete(self, *args, **kwargs):
        """删除项目时同时删除项目目录"""
        if os.path.exists(self.project_path):
            shutil.rmtree(self.project_path)
        super().delete(*args, **kwargs)


class ProjectVersionModel(models.Model):
    """项目版本模型"""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    project = models.ForeignKey(ProjectModel, on_delete=models.CASCADE, related_name="versions", verbose_name="项目")
    version = models.IntegerField(verbose_name="版本号")
    content = models.TextField(verbose_name="markdown内容")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    creator = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="创建者")
    
    class Meta:
        db_table = "project_version"
        ordering = ["-version"]
        unique_together = ['project', 'version']
        verbose_name = "项目版本"
        verbose_name_plural = "项目版本"

    def __str__(self):
        return f"{self.project.name} v{self.version}"
